<template>
  <div id="ROBOT">
    <canvas id="canvas"></canvas>

    <div class="waves" v-show="isSpeak">
      <div class="wave one"></div>
      <div class="wave two"></div>
      <div class="wave three"></div>
      <div class="wave four"></div>
      <div class="wave five"></div>
      <div class="wave six"></div>
      <div class="wave seven"></div>
    </div>
    <div :class="[{ 'speak-bg': isSpeak }, 'icon']">
      <div class="left" @click="drop">
        <img src="@/assets/robot/drop.svg" alt="">
      </div>
      <div class="mid speak-btn" v-show="!isWirte" @click="speak">
        {{ midTxt }}
      </div>
      <div class="mid write-btn" v-show="isWirte">
        <el-input v-model="userMessage" placeholder="有问题就来问我哦~" @keydown.enter="handleMessageEnter">
          <template #suffix>
            <el-icon class="el-input__icon" @click="handleMessageEnter">
              <Position />
            </el-icon>
          </template>
        </el-input>
        <!-- <Field v-model="userMessage" @click-right-icon="handleMessageEnter" right-icon="guide-o"
          placeholder="有问题就来问我哦~" /> -->
      </div>
      <div class="rig rig-btn rig-keyboard" v-show="!isWirte" @click="sendMessage">
        <img src="@/assets/robot/keyboard.svg" alt="">
      </div>
      <div class="rig rig-btn rig-microphone" v-show="isWirte" @click="isWirte = false">
        <img src="@/assets/robot/microphone.svg" alt="">
      </div>
    </div>

    <div v-if="chatCurrentList.length > 0" ref="chatMainMessagesRef" class="message-widget">
      <div class="list" v-for="(item, index) in chatCurrentList" :key="index">
        <div class="circle circle-user" v-if="item.chatType === 'user'">
          <div class="child"></div>
        </div>
        <div class="circle circle-bot" v-if="item.chatType === 'bot'">
          <div class="child"></div>
        </div>
        <div class="ai_loading" v-if="item.chatType === 'bot' && item.message === ''" />
        <div v-if="item.chatType === 'user'">{{ item.message }}</div>
        <div class="chat-bot" v-else v-html="getMdiText(item.message)" />
      </div>
    </div>
    <audio id="aloading" autoplay preload="auto"></audio>
  </div>
</template>

<script lang="ts" setup>
import { APITtsAdd } from "@/api/ApiSpeechModel"
import Speech from "@/utils/speech"
import type { Action } from 'element-plus'
import { ElMessage, ElMessageBox } from "element-plus"
import { onMounted, ref } from "vue"
// import { showConfirmDialog, Field, showFailToast } from 'vant';
import useMarkdown from "@/hooks/useMarkdown/useMarkdown"
import useLive from "./useLive"
const { getMdiText } = useMarkdown()
const authorizationToken = ref<string>("")
// const userMessage = ref<string>("")
const midTxt = ref<string>("点击对话")
const isSpeak = ref(false)
const isWirte = ref(false)

interface RobotProps {
  voice_id: number
}

let ROBOT
const {
  userMessage,
  chatMainMessagesRef,
  chatBoolTextEnd,
  chatCurrentList,
  handleMessageEnter,
  handleScrollToBottom,
} = useLive()

const emits = defineEmits(['close'])
const props = withDefaults(defineProps<RobotProps>(),{
  voice_id: 38
})

async function drawCanvas() {
  const canvas = document.getElementById("canvas")
  const robotDom = document.getElementById('ROBOT')
  const width = robotDom?.clientWidth ?? 0
  const height = robotDom?.clientHeight ?? 0
  const app = new PIXI.Application({
    view: canvas,
    resizeTo: robotDom,
    // backgroundColor: 0xffffff
  })

  const bg_sy = import.meta.env.VITE_DEV_PRO_META === 'development' ? '../../../public/bg_sy.png' : '/bg_sy.png'
  const Cha_RobotStyleA = import.meta.env.VITE_DEV_PRO_META === 'development' ? '../../../public/m2/Cha_RobotStyleA.model3.json' : '/m2/Cha_RobotStyleA.model3.json'

  const texture = PIXI.Texture.from(bg_sy);
  const bgSprite = new PIXI.Sprite(texture);
  bgSprite.width = app.screen.width;
  bgSprite.height = app.screen.height;
  // bgSprite.x = (app.screen.width - bgSprite.width) / 2;
  // bgSprite.y = (app.screen.height - bgSprite.height) / 2;
  app.stage.addChild(bgSprite);

  const models = await Promise.all([PIXI.live2d.Live2DModel.from(Cha_RobotStyleA)])
  models.forEach(model => {
    const scaleX = (width * 1) / model.width;
    const scaleY = (height * 1) / model.height;
    model.scale.set(scaleX * 1.2);
    model.y = height * 0.05;
    model.x = (width - model.width) / 2;
    ROBOT = model
    ROBOT.expression("Style_CatEars")
    // ROBOT.internalaction = true
    ROBOT.autoInteract = false
    console.log(ROBOT);

    app.stage.addChild(ROBOT)
  })
}
function getAuthorizationToken() {
  const fetchUrl =
    // "https://robot.lnkyeah.com"
    // "https://earphone.lnkyeah.com"
    "/chat_msg"
  const authorizationEndpoint = `${fetchUrl}/index/index/speek`
  if (authorizationEndpoint) {
    const a = new XMLHttpRequest()
    a.open("GET", authorizationEndpoint)
    a.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
    a.send("")
    a.onload = (res: any) => {
      // const token = JSON.parse(atob(res.target.responseText.split(".")[1]))
      // const regionOptions = token.region
      // console.log("建立语音链接成功", regionOptions)
      authorizationToken.value = res.target.responseText
    }
  }
}
async function getVoiceURL(userMessage: string) {
  let params = {
    voice_id: props.voice_id,
    messages: userMessage
  }
  let { code } = await APITtsAdd(params)
  if (code === 200) {
    Speech.instance.on("tts", async (msg: any) => {
      console.log("socket语音返回 :>> ", msg.url)
      if (msg && msg.url) {
        ROBOT.speak(msg.url, 1)
      }
    })
  } else {
    // showFailToast("声音返回失败")
    ElMessage.error('声音返回失败')
  }

}
function showDialog() {
  ElMessageBox.confirm(
    '为了您与数字人对话时的体验完整，请打开声音',
    '开启对话声音',
    {
      distinguishCancelAndClose: true,
      confirmButtonText: '打开声音',
      cancelButtonText: '静音体验',
    }
  )
    .then(() => {
      getVoiceURL("你好")
      chatCurrentList.value.push({
        chatType: "bot",
        message: '你好'
      })
    })
    .catch((action: Action) => {

    })
  /**
    showConfirmDialog({
      title: '开启对话声音',
      message: '为了您与数字人对话时的体验完整，请打开声音',
      confirmButtonText: '打开声音',
      cancelButtonText: '静音体验'
    })
      .then(() => {
        // on confirm
        getVoiceURL("你好，派大星派大星派大星")
      })
      .catch(() => {
        // on cancel
      });
  */
}
function sendMessage() {
  isWirte.value = true
  isSpeak.value = false
  midTxt.value = "点击对话"
}
function saveChatDataToLocal(list) {
  let res
  if (list.length > 300) {
    res = list.slice(-300)
  } else {
    res = list
  }
  chatCurrentList.value = res
}
function insertGptToAllData(message) {
  let _allData = JSON.parse(JSON.stringify(chatCurrentList.value))
  let lastMsg = _allData[_allData.length - 1]
  if (lastMsg.chatType === "bot") {
    lastMsg.message += message.text
  } else {
    lastMsg = [{ chatType: "bot", message }]
  }
  saveChatDataToLocal(_allData)
  handleScrollToBottom()
}
function speak() {
  isSpeak.value = true
  midTxt.value = "录音中···"
  startRecording()
}
function startRecording() {
  // 使用默认的麦克风输入
  const audioConfig = window.SpeechSDK.AudioConfig.fromDefaultMicrophoneInput()
  // 创建语音配置
  const speechConfig = window.SpeechSDK.SpeechConfig.fromAuthorizationToken(authorizationToken.value, "eastus")
  speechConfig.speechRecognitionLanguage = "zh-CN"
  // 创建语音识别器
  const recognizer = new window.SpeechSDK.SpeechRecognizer(speechConfig, audioConfig)
  console.log("调起了麦克风", recognizer)
  recognizer.recognizeOnceAsync(
    async (result: any) => {
      const recognizedText = result.text
      console.log("返回语音解析", recognizedText)
      await recognizer.close()
      isSpeak.value = false
      midTxt.value = "点击对话"
      userMessage.value = recognizedText
      handleMessageEnter()
    },
    (error: any) => {
      ElMessage.error('麦克风启动失败')
      recognizer.close()
      setTimeout(() => {
        isSpeak.value = false
      }, 1000);

    }
  )
}

function drop() {
  emits('close', false)
  // console.log('挂断对话');
}
onMounted(() => {
  getAuthorizationToken()
  drawCanvas()
  showDialog()
  Speech.instance.on("chat_text", (msg: any) => {
    insertGptToAllData(msg)
  })
  Speech.instance.on("chat_text_end", (msg: any) => {
    chatBoolTextEnd.value = false;
    console.log(chatCurrentList.value);

  })
  Speech.instance.on("chat_audio", (msg: any) => {
    // console.log("chat_audio", msg);
    /*  msg返回格式为msg={messages_id:'111112222',url:'http://xxx.mp3'} */
    if (msg && msg.url) {
      ROBOT.speak(msg.url, 1)
    }
  })
  Speech.instance.on("chat_audio_end", (msg: any) => {
    // console.log("chat_audio_end", msg);
    /*  msg返回格式为msg={messages_id:'111112222'} */
    chatBoolTextEnd.value = false
  })
})

</script>

<style lang="scss" scoped>
#ROBOT {
  position: relative;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 500px;
  height: 100%;

  #canvas {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: 100%;
  }
}

.speak-bg {
  background: url("../../assets/robot/voice-bg.svg") no-repeat center center;
}

.icon {
  width: 100%;
  // height: 150px;
  height: 210px;
  position: fixed;
  bottom: 0;
  display: flex;
  justify-content: center;
  align-items: end;
  cursor: pointer;
  padding: 30px 20px;

  .left {
    height: 48px;
  }

  .mid {
    margin: 0 10px;
  }

  ::v-deep .el-input__wrapper {
    border-radius: 24px;
    height: 48px;
  }

  // .van-field {
  //   border-radius: 24px;
  //   height: 48px;
  // }

  .speak-btn {
    width: 187px;
    height: 48px;
    background: url("../../assets/robot/speak-btn.svg") no-repeat center center;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
  }

  .rig {
    &-btn {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 48px;
      height: 48px;
      border-radius: 50%;
    }

    &-keyboard {
      background-color: #fff;
    }

    &-microphone {
      background-color: #406FFDE5;
    }
  }
}

@keyframes yuying {
  0% {
    height: 10%;
  }

  20% {
    height: 50%;
  }

  50% {
    height: 100%;
  }

  80% {
    height: 50%;
  }

  100% {
    height: 0%;
  }
}

.waves {
  width: 100%;
  height: 40px;
  position: fixed;
  bottom: 100px;
  z-index: 9;
  text-align: center;

  .wave {
    width: 6px;
    height: 100%;
    margin-left: 10px;
    border-radius: 50px;
    background-color: #406EFD;
    vertical-align: middle;
    display: inline-block;
  }

  .one {
    animation: yuying 0.6s infinite 0.1s;
    -webkit-animation: yuying 0.6s infinite 0.1s;
  }

  .two {
    animation: yuying 0.6s infinite 0.3s;
    -webkit-animation: yuying 0.6s infinite 0.3s;
  }

  .three {
    animation: yuying 0.6s infinite 0.5s;
    -webkit-animation: yuying 0.6s infinite 0.5s;
  }

  .four {
    animation: yuying 0.6s infinite 0.7s;
    -webkit-animation: yuying 0.6s infinite 0.7s;
  }

  .five {
    animation: yuying 0.6s infinite 0.9s;
    -webkit-animation: yuying 0.6s infinite 0.9s;
  }

  .six {
    animation: yuying 0.6s infinite 1.1s;
    -webkit-animation: yuying 0.6s infinite 1.1s;
  }

  .seven {
    animation: yuying 0.6s infinite 1.3s;
    -webkit-animation: yuying 0.6s infinite 1.3s;
  }
}

.message-widget {
  position: fixed;
  bottom: 150px;
  max-height: 300px;
  overflow-y: scroll;
  padding: 0 12px;
  color: #fff;
  font-size: 14px;

  &::-webkit-scrollbar {
    width: 8px;
    height: 8px;
  }

  // 滚动条上的滚动滑块
  &::-webkit-scrollbar-thumb {
    border-radius: 4px;
    background-color: #90939955;
  }

  &::-webkit-scrollbar-thumb:hover {
    background-color: #90939977;
  }

  &::-webkit-scrollbar-thumb:active {
    background-color: #90939999;
  }

  .list {
    display: flex;
    margin-bottom: 20px;

    .circle {
      display: flex;
      align-items: center;
      justify-content: center;
      flex: 0 0 12px;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      /* margin-right: 10px; */
      margin: 4px 8px 0 0;

      .child {
        width: 6px;
        height: 6px;
        border-radius: 50%;
      }

      &-user {
        background-color: #B4B5BA;

        .child {
          background-color: #657085;
        }

      }

      &-bot {
        background-color: #B1B7DE;

        .child {
          background-color: #4059FD;
        }

      }
    }
  }

  .ai_loading {
    &::after {
      content: "...";
      margin-bottom: 10px;
      animation: ellipsis 1.2s infinite;
    }

    @keyframes ellipsis {

      0%,
      100% {
        content: "...";
      }

      33% {
        content: ".. ";
      }

      66% {
        content: ".  ";
      }
    }
  }
}
</style>import { env } from "process"
